#include "line.h"
#include <qDebug>

Line::Line( int w, int h, int spd, QObject *parent )
    :QThread( parent ), width( w ), height( h ), speed( spd )
{
    make_a_start();
    color = QColor( static_cast<Qt::GlobalColor>( qrand() % 16 + 4 ) );
}

void Line::run()
{
    //qDebug() << "draw";
    while( cur_stage == Draw )
    {
        draw_a_step();
        update();
        msleep( 30 );
    }
    //qDebug() << "show";
    while( cur_stage == Show )
    {
        show_a_step();
        update();
        msleep( 30 );
    }
    //qDebug() << "fade";
    while( cur_stage == Fade )
    {
        fade_a_step();
        update();
        msleep( 30 );
    }
    //qDebug() << "dead";
}

void Line::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    QPen pen( color );
    pen.setMiterLimit( 8 );
    pen.setJoinStyle( Qt::RoundJoin );
    pen.setCapStyle( Qt::RoundCap );
    pen.setWidth( 5 );
    painter->setPen( pen );
    painter->drawLines( lines );
}



void Line::make_a_start()
{
    life_timer = 0;
    turn_timer = (int) ExpArrival::newArrival( DEF_TRATE, DEF_TMIN );
    fade_timer = DEF_FADE;
    show_timer = DEF_SHOW;

    int xoff = - width / 2, yoff = - height / 2;

    switch( qrand() % 12 )
    {
    case 0:
        xoff += qrand() % width;
        cur_direct = SW;
        break;
    case 1:
        xoff += qrand() % width;
        cur_direct = SE;
        break;
    case 2:
        xoff += qrand() % width;
        cur_direct = S;
        break;

    case 3:
        xoff = width / 2;
        yoff += qrand() % height;
        cur_direct = NW;
        break;
    case 4:
        xoff = width / 2;
        yoff += qrand() % height;
        cur_direct = SW;
        break;
    case 5:
        xoff = width / 2;
        yoff += qrand() % height;
        cur_direct = W;
        break;

    case 6:
        xoff += qrand() % width;
        yoff = height / 2;
        cur_direct = NW;
        break;
    case 7:
        xoff += qrand() % width;
        yoff = height / 2;
        cur_direct = NE;
        break;
    case 8:
        xoff += qrand() % width;
        yoff = height / 2;
        cur_direct = N;
        break;

    case 9:
        yoff += qrand() % height;
        cur_direct = NE;
        break;
    case 10:
        yoff += qrand() % height;
        cur_direct = SE;
        break;
    case 11:
        yoff += qrand() % height;
        cur_direct = E;
        break;
    }
    cur_pointer = QPoint( xoff, yoff );
    lines.append( QLine( cur_pointer, cur_pointer ) );
    cur_stage = Draw;
}

void Line::make_a_turn()
{
    lines.append( QLine( cur_pointer, cur_pointer ) );
    int t = cur_direct;
    t += ( rand() % 2 ) * 2 - 1;
    t = ( t + 8 ) % 8;
    cur_direct = static_cast<Direction>( t );
    turn_timer = (int) ExpArrival::newArrival( DEF_TRATE, DEF_TMIN );
}

void Line::draw_a_step()
{
    // if it is ready to make a turn
    if( !turn_timer )
    {
        make_a_turn();
    }
    QLine newline = lines.last();
    lines.pop_back();
    QPoint p2 = newline.p2();
    QPointF ext_vecf;
    switch( cur_direct )
    {
    case SW:
        ext_vecf = QPointF( - HRT, HRT );
        break;
    case SE:
        ext_vecf = QPointF( HRT, HRT );
        break;
    case NW:
        ext_vecf = QPointF( -HRT, -HRT );
        break;
    case NE:
        ext_vecf = QPointF( HRT, -HRT );
        break;
    case S:
        ext_vecf = QPointF( 0, 1 );
        break;
    case N:
        ext_vecf = QPointF( 0, -1 );
        break;
    case W:
        ext_vecf = QPointF( -1, 0 );
        break;
    case E:
        ext_vecf = QPointF( 1, 0 );
        break;
    }
    ext_vecf *= speed;
    QPoint ext_vec( ext_vecf.x(), ext_vecf.y() );
    p2 += ext_vec;

    // check if p2 is out of bound
    if( p2.x() > width / 2 )
    {
        p2.setX( width / 2 );
        cur_stage = Show;
        finish_time = life_timer;
    }
    if ( p2.x() < - width / 2 )
    {
        p2.setX( -width / 2 );
        cur_stage = Show;
        finish_time = life_timer;
    }
    if ( p2.y() > height / 2 )
    {
        p2.setY( height / 2 );
        cur_stage = Show;
        finish_time = life_timer;
    }
    if ( p2.y() < -height / 2 )
    {
        p2.setY( - height / 2 );
        cur_stage = Show;
        finish_time = life_timer;
    }
    newline.setP2( p2 );
    lines.push_back( newline );

    cur_pointer = p2;

    life_timer ++;
    turn_timer --;
}

void Line::show_a_step()
{
    life_timer ++;
    if( show_timer -- < 0 )
    {
        cur_stage = Fade;
    }
}

void Line::fade_a_step()
{
    life_timer ++;
    if( fade_timer -- < 0 )
    {
       cur_stage = Dead;
    }
    else
    {
        this->setOpacity( (qreal)fade_timer / DEF_FADE );
    }

}

void Line::mousePressEvent( QGraphicsSceneMouseEvent *event )
{

}
